package com.njcb.ams.support.trade.filter;

import com.google.common.collect.Lists;
import com.njcb.ams.factory.domain.AppContext;
import com.njcb.ams.support.annotation.TradeFilter;
import com.njcb.ams.support.exception.ExceptionCode;
import com.njcb.ams.support.exception.ExceptionUtil;
import com.njcb.ams.util.AmsJsonUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Set;

/**
 * @author liuyanlong
 */
@Service
@Lazy(false)
@TradeFilter(priority = 0)
public class ParamValidateFilter implements TradeLayerFilter {
    private static final Logger logger = LoggerFactory.getLogger(ParamValidateFilter.class);

    @Resource
    private Validator validator;

    public static ParamValidateFilter getInstance() {
        return AppContext.getBean(ParamValidateFilter.class);
    }

    @Override
    public Object doFilter(TradeFilterChain filterChain) throws Throwable {
        ProceedingJoinPoint pjd = filterChain.getJoinPoint();
        Object[] args = pjd.getArgs();
        Class<?>[] groups = determineValidationGroups(pjd);
        List<String> messages = Lists.newArrayList();
        for (int i = 0; i < args.length; i++) {
            if(null!=args[i]) {
                Set<ConstraintViolation<Object>> constraintViolations = validator.validate(args[i], groups);
                for (ConstraintViolation<Object> error : constraintViolations) {
                    messages.add(error.getMessage() + "[" + error.getPropertyPath() + "]");
                }
            }
        }
        if (!messages.isEmpty()) {
            ExceptionUtil.throwAppException(AmsJsonUtils.objectToJson(messages), ExceptionCode.PARAM_VALIDATE_FAIL);
        }
        Object result = filterChain.doFilter(filterChain);
        return result;
    }

    private Class<?>[] determineValidationGroups(ProceedingJoinPoint pjd) {
        Object signature = pjd.getSignature();
        Validated validatedAnn = null;
        if (signature instanceof MethodSignature) {
            MethodSignature methodSignature = (MethodSignature) signature;
            // 获取方法上的注解
            validatedAnn = methodSignature.getMethod().getAnnotation(Validated.class);
            //获取所有参数上的注解
            if (null == validatedAnn) {
                Annotation[][] parameterAnnotations = methodSignature.getMethod().getParameterAnnotations();
                if (null != parameterAnnotations) {
                    for (int i = 0; i < parameterAnnotations.length; i++) {
                        Annotation[] annotations = parameterAnnotations[i];
                        for (int j = 0; j < annotations.length; j++) {
                            Annotation ann = annotations[j];
                            if (ann instanceof Validated) {
                                validatedAnn = (Validated) ann;
                            }
                        }
                    }
                }
            }
        }
        return validatedAnn != null ? validatedAnn.value() : new Class[0];
    }

}
